www.gusucode.com > C++ 实现可控的3D旋转立方体-源码程序 > C++ 实现可控的3D旋转立方体-源码程序/code/Scene.cpp

    // Scene.cpp: implementation of the CScene class.
// Download by http://www.NewXing.com
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include <math.h>
#include "2DCube.h"
#include "Scene.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CScene::CScene()
{}

CScene::~CScene()
{}

int CScene::SetMatrix(int matkind,Matrix * mat)
{
	if( NULL == mat ) 
		return 0;
	
	switch (matkind)
	{
	case MAT_WORLD:
		memcpy( (void *)&m_WorldMatrix , (void *)mat , sizeof(Matrix) );
		break;
		
	case MAT_VIEW:
		memcpy( (void *)&m_ViewMatrix , (void *)mat , sizeof(Matrix) );
		break;
		
	case MAT_PROJ:
		memcpy( (void *)&m_ProjMatrix , (void *)mat , sizeof(Matrix) );
		break;
	default:
		break;
	}
	return 1;
}

//SetProjection用于把一个矩阵设置为透视投影矩阵。
Matrix * CScene::SetProjection(Matrix * projmat,float nearclip, float farclip, float fov)
{
	IdentifyMatrix(projmat);
	projmat ->_a43	= 1/nearclip; 
	projmat ->_a44	= 0;
	return projmat;
}

//SetViewLookAt函数用于把一个矩阵设置为视矩阵。其实现如下:
Matrix * CScene::SetViewLookAt(Matrix * matView,Vert3 *vlookat, Vert3 *vEye, Vert3 *updir)
{
	Vert3	u,v,n;
	Matrix	matvrp;
	float	mo;
	
	n.x = vlookat->x - vEye->x; //计算向量n
	n.y = vlookat->y - vEye->y;
	n.z = vlookat->z - vEye->z;
	
	ChaMult(&u,updir,&n); //updir叉乘n得到u
	ChaMult(&v,&n,&u); //n叉乘u得到v
	mo	= ::sqrtf(u.x * u.x + u.y * u.y + u.z * u.z);//计算向量模长
	u.x /= mo; //化为单位向量
	u.y /= mo;
	u.z /= mo;
	mo = ::sqrtf(v.x * v.x + v.y * v.y + v.z * v.z);
	v.x /= mo;
	v.y /= mo;
	v.z /= mo;
	mo = ::sqrtf(n.x * n.x + n.y * n.y + n.z * n.z);
	n.x /= mo;
	n.y /= mo;
	n.z /= mo;
	
	IdentifyMatrix(matView); //设置复合的旋转矩阵
	
	matView->_a11	= u.x;
	matView->_a12	= u.y;
	matView->_a13	= u.z;
	
	matView->_a21	= v.x;
	matView->_a22	= v.y;
	matView->_a23	= v.z;
	
	matView->_a31	= n.x;
	matView->_a32	= n.y;
	matView->_a33	= n.z;
	
	IdentifyMatrix(&matvrp); //设置平移矩阵
	
	matvrp._a14 = -vEye->x;
	matvrp._a24 = -vEye->y;
	matvrp._a34 = -vEye->z;
	
	MultMatrix(matView,matView,&matvrp); //两矩阵相乘,得到最终的变换矩阵
	return matView;
	
}

//矩阵右乘表示摄像机位置的矩阵matvrp实现摄像机的平移,得到最终的视矩阵。
//函数IdentifyMatrix把一个矩阵单位化:
Matrix * CScene::IdentifyMatrix(Matrix * mat)
{
	mat->_a11	= 1.0f;
	mat->_a12	= 0.0f;
	mat->_a13	= 0.0f;
	mat->_a14	= 0.0f;
	
	mat->_a21	= 0.0f;
	mat->_a22	= 1.0f;
	mat->_a23	= 0.0f;
	mat->_a24	= 0.0f;
	
	mat->_a31	= 0.0f;
	mat->_a32	= 0.0f;
	mat->_a33	= 1.0f;
	mat->_a34	= 0.0f;
	
	mat->_a41	= 0.0f;
	mat->_a42	= 0.0f;
	mat->_a43	= 0.0f;
	mat->_a44	= 1.0f;
	
	return mat;
}

//函数MatRotation把一个矩阵设置为旋转变换矩阵。其实现如下:
Matrix * CScene::MatRotation(Matrix * mat,float alpha,int axis)
{
	float sinalpha = (float)sin(alpha);
	float cosalpha = (float)cos(alpha);
	
	switch (axis) //依照参数值设置关于不同轴的旋转矩阵
	{
	case AXIS_X:
		{
			mat->_a11	= 1.0f; 
			mat->_a12	= 0.0f; 
			mat->_a13	= 0.0f; 
			mat->_a14	= 0.0f;
			
			mat->_a21	= 0.0f; 
			mat->_a22	= cosalpha; 
			mat->_a23	= -sinalpha; 
			mat->_a24	=0.0f ;
			
			mat->_a31	= 0.0f; 
			mat->_a32	= sinalpha; 
			mat->_a33	= cosalpha; 
			mat->_a34	= 0.0f;
			
			mat->_a41	= 0.0f; 
			mat->_a42	= 0.0f; 
			mat->_a43	= 0.0f; 
			mat->_a44	= 1.0f;
		}
		
		break;
		
	case AXIS_Y:
		{
			mat ->_a11	= cosalpha; 
			mat ->_a12	= 0.0f;
			mat ->_a13	= sinalpha; 
			mat	->_a14	= 0.0f;
			
			mat ->_a21	= 0.0f; 
			mat ->_a22	= 1.0f;
			mat ->_a23	= 0.0f; 
			mat ->_a24	= 0.0f;
			
			mat ->_a31	= -sinalpha;
			mat ->_a32	= 0.0f;
			mat ->_a33	= cosalpha; 
			mat ->_a34	= 0.0f;
			
			mat ->_a41	= 0.0f; 
			mat ->_a42	= 0.0f;
			mat ->_a43	= 0.0f; 
			mat ->_a44	= 1.0f;
		}
		break;
	case AXIS_Z:
		{
			mat ->_a11	= cosalpha; 
			mat ->_a12	= -sinalpha; 
			mat ->_a13	= 0.0f; 
			mat ->_a14	= 0.0f;
			
			mat ->_a21	= sinalpha; 
			mat ->_a22	= cosalpha; 
			mat ->_a23	= 0.0f; 
			mat	->_a24	= 0.0f;
			
			mat ->_a31	= 0.0f; 
			mat ->_a32	= 0.0f; 
			mat ->_a33	= 1.0f; 
			mat ->_a34	= 0.0f;
			
			mat ->_a41	= 0.0f; 
			mat ->_a42	= 0.0f; 
			mat ->_a43	= 0.0f; 
			mat ->_a44	= 1.0f;
		}
		break;
		
	default:
		break;
	}
	
	return mat;
}


//函数MatTranslation与MatRotation类似,它完成把一个矩阵设为平移变换矩阵的工作。其实现如下:
//函数的第一个参数是要被设置的矩阵,第二个参数是旋转的角度,第三个参数是旋转轴,必须为上面三个宏中的一个。该函数针对不同轴的旋转,把矩阵设为三种旋转矩阵中的一种。
Matrix * CScene::MatTranslation(Matrix * mat,float xoffset,float yoffset,float zoffset)
{
	mat ->_a11	= 1.0f;
	mat ->_a12	= 0.0f;
	mat ->_a13	= 0.0f;
	mat ->_a14	= xoffset;
	
	mat ->_a21	= 0.0f;
	mat ->_a22	= 1.0f;
	mat ->_a23	= 0.0f;
	mat ->_a24	= yoffset;
	
	mat ->_a31	= 0.0f;
	mat ->_a32	= 0.0f;
	mat ->_a33	= 1.0f;
	mat ->_a34	= zoffset;
	
	mat ->_a41	= 0.0f;
	mat ->_a42	= 0.0f;
	mat ->_a43	= 0.0f;
	mat ->_a44	= 1.0f;
	
	return mat;
}

//函数MultMatrix实现矩阵乘法:
Matrix * CScene::MultMatrix(Matrix * outmat,Matrix * inmat1,Matrix * inmat2)
{
	Matrix matout;
	matout._a11 = (inmat1 ->_a11) * (inmat2 ->_a11) + (inmat1 ->_a12) * (inmat2 ->_a21) + (inmat1 ->_a13) * (inmat2 ->_a31) + (inmat1 ->_a14) * (inmat2 ->_a41) ; 
	matout._a12 = (inmat1 ->_a11) * (inmat2 ->_a12) + (inmat1 ->_a12) * (inmat2 ->_a22) + (inmat1 ->_a13) * (inmat2 ->_a32) + (inmat1 ->_a14) * (inmat2 ->_a42) ;
	matout._a13 = (inmat1 ->_a11) * (inmat2 ->_a13) + (inmat1 ->_a12) * (inmat2 ->_a23) + (inmat1 ->_a13) * (inmat2 ->_a33) + (inmat1 ->_a14) * (inmat2 ->_a43) ;
	matout._a14 = (inmat1 ->_a11) * (inmat2 ->_a14) + (inmat1 ->_a12) * (inmat2 ->_a24) + (inmat1 ->_a13) * (inmat2 ->_a34) + (inmat1 ->_a14) * (inmat2 ->_a44) ;
	
	matout._a21 = (inmat1 ->_a21) * (inmat2 ->_a11) + (inmat1 ->_a22) * (inmat2 ->_a21) + (inmat1 ->_a23) * (inmat2 ->_a31) + (inmat1 ->_a24) * (inmat2 ->_a41) ;
	matout._a22 = (inmat1 ->_a21) * (inmat2 ->_a12) + (inmat1 ->_a22) * (inmat2 ->_a22) + (inmat1 ->_a23) * (inmat2 ->_a32) + (inmat1 ->_a24) * (inmat2 ->_a42) ;
	matout._a23 = (inmat1 ->_a21) * (inmat2 ->_a13) + (inmat1 ->_a22) * (inmat2 ->_a23) + (inmat1 ->_a23) * (inmat2 ->_a33) + (inmat1 ->_a24) * (inmat2 ->_a43) ;
	matout._a24 = (inmat1 ->_a21) * (inmat2 ->_a14) + (inmat1 ->_a22) * (inmat2 ->_a24) + (inmat1 ->_a23) * (inmat2 ->_a34) + (inmat1 ->_a24) * (inmat2 ->_a44) ;
	
	matout._a31 = (inmat1 ->_a31) * (inmat2 ->_a11) + (inmat1 ->_a32) * (inmat2 ->_a21) + (inmat1 ->_a33) * (inmat2 ->_a31) + (inmat1 ->_a34) * (inmat2 ->_a41) ;
	matout._a32 = (inmat1 ->_a31) * (inmat2 ->_a12) + (inmat1 ->_a32) * (inmat2 ->_a22) + (inmat1 ->_a33) * (inmat2 ->_a32) + (inmat1 ->_a34) * (inmat2 ->_a42) ;
	matout._a33 = (inmat1 ->_a31) * (inmat2 ->_a13) + (inmat1 ->_a32) * (inmat2 ->_a23) + (inmat1 ->_a33) * (inmat2 ->_a33) + (inmat1 ->_a34) * (inmat2 ->_a43) ;
	matout._a34 = (inmat1 ->_a31) * (inmat2 ->_a14) + (inmat1 ->_a32) * (inmat2 ->_a24) + (inmat1 ->_a33) * (inmat2 ->_a34) + (inmat1 ->_a34) * (inmat2 ->_a44) ;
	
	matout._a41 = (inmat1 ->_a41) * (inmat2 ->_a11) + (inmat1 ->_a42) * (inmat2 ->_a21) + (inmat1 ->_a43) * (inmat2 ->_a31) + (inmat1 ->_a44) * (inmat2 ->_a41) ;
	matout._a42 = (inmat1 ->_a41) * (inmat2 ->_a12) + (inmat1 ->_a42) * (inmat2 ->_a22) + (inmat1 ->_a43) * (inmat2 ->_a32) + (inmat1 ->_a44) * (inmat2 ->_a42) ;
	matout._a43 = (inmat1 ->_a41) * (inmat2 ->_a13) + (inmat1 ->_a42) * (inmat2 ->_a23) + (inmat1 ->_a43) * (inmat2 ->_a33) + (inmat1 ->_a44) * (inmat2 ->_a43) ;
	matout._a44 = (inmat1 ->_a41) * (inmat2 ->_a14) + (inmat1 ->_a42) * (inmat2 ->_a24) + (inmat1 ->_a43) * (inmat2 ->_a34) + (inmat1 ->_a44) * (inmat2 ->_a44) ;
	
	memcpy( (void *)outmat , (void *)&matout , sizeof(Matrix) );
	
	return outmat;
}

//DrawPrimtive函数。它的作用是依照设置的三种矩阵的变换,在显示器上绘制vertexbuf中所有点表示的多边形图元。其实现如下:
void CScene::DrawPrimtive(HDC hdc,int nVertex,Vert3 * vertexbuf)
{
	Matrix matcombined; //用于纪录矩阵运算结果
	IdentifyMatrix(&matcombined);
	//依次与三个矩阵相乘
	MultMatrix( &matcombined , &matcombined , &m_ProjMatrix );
	MultMatrix( &matcombined , &matcombined , &m_ViewMatrix );
	MultMatrix( &matcombined , &matcombined , &m_WorldMatrix );
	Vert3 destcur ;
	Vert3 destlast;
	Vert3 * sourcecur = vertexbuf;
	
	SetPixel( hdc , 0 , 0 , RGB(0,0,0) );
	MultVertWithMatrix( &destlast , sourcecur , &matcombined );		//将向量与结果矩阵相乘,得到//变换后的向量
	sourcecur ++;
	//循环绘制多边形图元所有的边
	for (int j = 1 ; j < nVertex ; j++ )
	{
		MoveToEx( hdc , 100 + (int)destlast.x / destlast.w , 100 + (int)destlast.y / destlast.w , NULL );
		
		MultVertWithMatrix( &destcur , sourcecur , &matcombined );
		
		LineTo( hdc , 100 + (int)destcur.x / destcur.w , 100 + (int)destcur.y / destcur.w );
		
		memcpy( (void * )&destlast , (void * )&destcur , sizeof(Vert3) );
		
		sourcecur ++;
	}//绘制到最后一个顶点;
	
	//把最后一个顶点与第一个相连;
	MoveToEx( hdc , 100 + (int)destlast.x / destlast.w , 100 + (int)destlast.y / destlast.w , NULL );
	MultVertWithMatrix( &destcur , vertexbuf , &matcombined );
	LineTo( hdc , 100 + (int)destcur.x / destcur.w , 100 + (int)destcur.y/destcur.w );
}


//DianMult:实现向量的点乘 
float CScene::DianMult(Vert3 *vertin1, Vert3 *vertin2)
{
	return ( (vertin1 ->x) * (vertin2 ->x) + (vertin1 ->y) * (vertin2 ->y) + (vertin1 ->z) * (vertin2 ->z) ) ;
	
}

//ChaMult:实现向量的叉乘
Vert3 * CScene::ChaMult(Vert3 *vertout, Vert3 *vertu, Vert3 *vertv)
{
	Vert3 out;
	
	out.x = (vertu ->y) * (vertv ->z) - (vertv ->y) * (vertu ->z) ;
	out.y = (vertv ->x) * (vertu ->z) - (vertu ->x) * (vertv ->z) ;
	out.z = (vertu ->x) * (vertv ->y) - (vertv ->x) * (vertu ->y) ;
	
	memcpy( vertout , &out , sizeof(Vert3) );
	
	return vertout;
}

//MultVertWithMatrix:实现向量与矩阵的乘法
void CScene::MultVertWithMatrix(Vert3 *vertout, Vert3 *vertin, Matrix *mat)
{
	vertout	->x = (mat ->_a11) * (vertin ->x) + (mat ->_a12) * (vertin ->y) + (mat ->_a13) * (vertin ->z) + (mat ->_a14) * (vertin ->w) ;
	vertout	->y = (mat ->_a21) * (vertin ->x) + (mat ->_a22) * (vertin ->y) + (mat ->_a23) * (vertin ->z) + (mat ->_a24) * (vertin ->w) ;
	vertout	->z = (mat ->_a31) * (vertin ->x) + (mat ->_a32) * (vertin ->y) + (mat ->_a33) * (vertin ->z) + (mat ->_a34) * (vertin ->w) ;
	vertout	->w = (mat ->_a41) * (vertin ->x) + (mat ->_a42) * (vertin ->y) + (mat ->_a43) * (vertin ->z) + (mat ->_a44) * (vertin ->w) ;
}